package com.link.base.core.basic.interceptors.mybatis.system;

import com.alibaba.fastjson.JSONObject;
import com.link.base.base.trackchild.model.Trackchild;
import com.link.base.base.trackdisplay.model.TrackDisplay;
import com.link.base.base.trackhead.model.Trackhead;
import com.link.base.user.model.CoreUser;
import com.link.core.basic.model.BasicModel;
import com.link.core.basic.service.KeyGenerateService;
import com.link.core.basic.service.snowflake.KeyGenerateUtil;
import com.link.core.cllog.LCLogger;
import com.link.core.util.StringUtils;
import com.link.core.util.UserUtil;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.delete.Delete;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Invocation;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author: qinxuegang
 * @Description:
 * @Date: 2018/11/1 11:54
 */
@Service("deleteInterceptor")
public class DeleteInterceptor implements SqlInterceptor {
    private static final Logger logger = LogManager.getLogger(DeleteInterceptor.class);
    @Resource
    private JdbcTemplate jdbcTemplate;
    @Resource
    private InterceptorUtils interceptorUtils;
    @Resource
    private KeyGenerateService keyGenerateService;
    /**
     * 识别sql中？
     */
    private static Pattern REPLACE_WHAT = Pattern.compile("\\?");

    @Override
    public String doInterceptor(Invocation invocation, BoundSql boundSql) {
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        Object parameterObject = boundSql.getParameterObject();
        Statement stmt = null;
        try {
            String updateSql = boundSql.getSql();
            String rgex = "/\\*.*?\\*/";
            updateSql = InterceptorUtils.getSubUtil(updateSql, rgex).toLowerCase();
            Object[] params = getWhere(parameterObject, parameterMappings);
            for (Object obj : params) {
                if (obj == null) {
                    updateSql = replaceFirst(null, updateSql);
                } else {
                    updateSql = replaceFirst(obj.toString(), updateSql);
                }
            }
            String [] sqlArray = updateSql.split(";");
            for (String tempSql : sqlArray) {
                updateSql = tempSql;
                stmt = CCJSqlParserUtil.parse(updateSql);
                Delete delete = (Delete) stmt;
                //表名
                List<Table> tables = delete.getTables();
                Set<String> set = new HashSet<>();
                for (Table table : tables) {
                    set.add(table.getName());
                }
                if (set.size() <= 0) {
                    set.add(delete.getTable().getName());
                    tables.add(delete.getTable());
                }
                Expression where = delete.getWhere();
                logger.info("获取redis");
                Map<String, Object> headAndChild = interceptorUtils.getHeadAndChild(set, "trackDel");
                if (headAndChild.get("trackheads") == null) {
                    return boundSql.getSql();
                }
                List<Trackhead> list = (List<Trackhead>) headAndChild.get("trackheads");
                if (list == null || list.size() <= 0) {
                    return boundSql.getSql();
                }
                logger.info("获取用户信息");
                CoreUser user = UserUtil.getUser();
//                Long batchNum = keyGenerateService.keyGenerate();
                //修改生成id的方式是为了适配目前的多数据源切换，使用keyGenerateService会将数据源切回为主数据源
                Long batchNum = KeyGenerateUtil.keyGenerate();
                for (Trackhead trackhead : list) {
                    for (Table table : tables) {
                        if (!trackhead.getTrackCode().equalsIgnoreCase(table.getName())) {
                            continue;
                        }
                        if (headAndChild.get("trackchilds") == null
                                || ((Map<String, List<Trackchild>>) headAndChild.get("trackchilds")).get(trackhead.getTrackCode()) == null) {
                            return boundSql.getSql();
                        }
                        List<Trackchild> listChild = ((Map<String, List<Trackchild>>) headAndChild.get("trackchilds")).get(trackhead.getTrackCode());
                        if (listChild == null || listChild.size() <= 0) {
                            continue;
                        }
                        StringBuilder sql = new StringBuilder("select ");
                        if (table.getAlias() != null && StringUtils.isNotBlank(table.getAlias().toString())) {
                            sql.append(table.getAlias().toString() + ".* from " + table.getName() + " " + table.getAlias().toString() + " where ");
                        } else {
                            sql.append("* from " + table.getName() + " where ");
                        }
                        if (where != null) {
                            sql.append(where.toString());
                        }
                        List<Map<String, Object>> listResult = jdbcTemplate.queryForList(sql.toString().toLowerCase());
                        logger.info("查询删除信息");
                        for (Map<String, Object> mapResult : listResult) {
                            for (Trackchild trackchild : listChild) {
                                String code = trackchild.getFieldCode();
                                Object resultObj = mapResult.get(code);
                                if (resultObj == null) {
                                    continue;
                                }
                                if (resultObj instanceof Timestamp && resultObj.toString().endsWith(".0")) {
                                    resultObj = resultObj.toString().substring(0, resultObj.toString().length() - 2);
                                }
                                if (InterceptorUtils.isDecimal(resultObj.toString())) {
                                    resultObj = InterceptorUtils.subZeroAndDot(resultObj.toString());
                                }
                                if (resultObj instanceof BigDecimal && resultObj != null && resultObj.toString().startsWith("0E")) {
                                    resultObj = "0";
                                }
                                TrackDisplay trackDisplay = new TrackDisplay();
                                trackDisplay.setUpdObjType(trackhead.getTrackName());
                                trackDisplay.setUpdObjCode(trackhead.getTrackCode());
                                trackDisplay.setBatchNum(batchNum);
                                trackDisplay.setUpdObjId(Long.parseLong(mapResult.get("row_id").toString()));
                                trackDisplay.setFieldName(trackchild.getFieldName());
                                trackDisplay.setFieldValue(trackchild.getFieldCode());
                                trackDisplay.setUpdBeforeInfo(resultObj.toString());
                                trackDisplay.setOperate("delete");
                                trackDisplay.setCorpid(user.getCorpid());
                                trackDisplay.setPostnId(user.getPostnId());
                                trackDisplay.setOrgId(user.getOrgId());
                                trackDisplay.setAttr77(user.getId());
                                trackDisplay.setAttr1(trackchild.getFieldType());
                                trackDisplay.setAttr2(trackchild.getLovType());
                                trackDisplay.setAttr3(trackchild.getDisplayName());
                                trackDisplay.setAttr4(trackchild.getDisplayValue());
                                logger.info("发送kafka信息");
                                logger.info(JSONObject.toJSON(trackDisplay).toString());
                                KafkaSender.sendInfo(KafkaSender.TRACK_TOPIC, JSONObject.toJSON(trackDisplay).toString());
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            LCLogger.withException(e);
        }
        return boundSql.getSql();
    }


    public static Object[] getWhere(Object parameterObject, List<ParameterMapping> parameterMappings)
            throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        BasicModel model = null;
        List<Object> list = new ArrayList<>();
        if (parameterObject == null) {
            throw new NullPointerException(" error，parameterObject is null!");
        }
        //这里加判断的原因是暂时只支持BasicModel的子类作为参数，List、Map等暂不支持
        if (!(parameterObject instanceof BasicModel)) {
            throw new IllegalArgumentException(" error，argument class must be extends BasicModel!");
        }
        model = (BasicModel) parameterObject;
        if (parameterMappings != null) {
            for (int i = 0; i < parameterMappings.size(); i++) {
                Method get = model.getClass().getMethod("get" + InterceptorUtils.getoUpperCaseChar(
                        parameterMappings.get(i).getProperty()), model.getClass().getDeclaredClasses());
                list.add(get.invoke(model));
            }
        }
        return list.toArray();
    }

    /**
     * 替换sql中的的？
     *
     * @param str
     * @param updateSql 传入的sql
     * @return 替换后的sql
     */
    public static String replaceFirst(String str, String updateSql) {
        if (org.apache.commons.lang3.StringUtils.isEmpty(str)) {
            str = "null";
        } else {
            str = "'" + str + "'";
        }
        Matcher m = REPLACE_WHAT.matcher(updateSql);
        String temp = m.replaceFirst(str);
        return temp;
    }
}
